package com.suneee.refund.service.impl;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.suneee.base.config.ServiceConfig;
import com.suneee.base.util.ContextHelper;
import com.suneee.base.util.JsonUtil;
import com.suneee.channel.dao.ChannelDao;
import com.suneee.channel.entity.Channel;
import com.suneee.context.page.Page;
import com.suneee.core.error.Assert;
import com.suneee.core.error.ErrorUtils;
import com.suneee.core.util.DateUtils;
import com.suneee.core.util.StringUtils;
import com.suneee.quartz.common.JobNameParams;
import com.suneee.quartz.common.QuartzJobCommonUtil;
import com.suneee.refund.address.bean.RefundAddress;
import com.suneee.refund.address.dao.RefundAddressDao;
import com.suneee.refund.bean.Condition;
import com.suneee.refund.bean.ViewRefundApplyWrap;
import com.suneee.refund.dao.RefundApplyDao;
import com.suneee.refund.dao.RefundCheckInfoDao;
import com.suneee.refund.dao.RefundCommentDao;
import com.suneee.refund.dao.ViewRefundApplyDao;
import com.suneee.refund.entity.RefundApply;
import com.suneee.refund.entity.RefundCheckInfo;
import com.suneee.refund.entity.RefundComment;
import com.suneee.refund.entity.ViewRefundApply;
import com.suneee.refund.job.RefundApplyDetailJob;
import com.suneee.refund.job.RefundApplyJob;
import com.suneee.refund.params.RefundParams;
import com.suneee.refund.params.ShopConnAttr;
import com.suneee.refund.service.RefundApplyService;
import com.suneee.refund.util.ReflectUtil;
import com.suneee.resources.ProductError;
import com.suneee.shop.dao.ShopDao;
import com.suneee.shop.entity.Shop;
import com.suneee.store.dao.ShopStockDao;
import com.suneee.store.dao.SpuDao;
import com.suneee.store.entity.ShopStock;
import com.suneee.store.entity.Spu;
import com.suneee.store.entity.StockDetail;
import com.suneee.store.entity.StockRecord;
import com.suneee.store.resources.StaticParam;
import com.suneee.store.service.IThirdPartyService;
import com.suneee.store.service.ProductService;
import com.suneee.store.service.ThirdPartyFactory;
import com.suneee.trades.dao.OrderLogDao;
import com.suneee.trades.dao.ShoppDao;
import com.suneee.trades.dao.ShoppDetailDao;
import com.suneee.trades.dao.TradesInfoDao;
import com.suneee.trades.dao.TradesOrderDao;
import com.suneee.trades.entity.Shopp;
import com.suneee.trades.entity.ShoppDetail;
import com.suneee.trades.entity.TradesInfo;
import com.suneee.trades.entity.TradesOrder;
import com.suneee.trades.resource.BusiType;
import com.suneee.trades.resource.OfflineStatus;
import com.suneee.trades.resource.ShoppStatus;
import com.suneee.trades.resource.ShoppType;
import com.suneee.trades.resource.TradesStatus;
import com.suneee.trades.service.TradesInfoService;
import com.taobao.api.ApiException;
import com.taobao.api.DefaultTaobaoClient;
import com.taobao.api.FileItem;
import com.taobao.api.TaobaoClient;
import com.taobao.api.domain.AddressResult;
import com.taobao.api.domain.RefundMappingResult;
import com.taobao.api.domain.RefundMessage;
import com.taobao.api.request.LogisticsAddressSearchRequest;
import com.taobao.api.request.RefundRefuseRequest;
import com.taobao.api.request.RpRefundReviewRequest;
import com.taobao.api.request.RpRefundsAgreeRequest;
import com.taobao.api.request.RpReturngoodsAgreeRequest;
import com.taobao.api.request.RpReturngoodsRefuseRequest;
import com.taobao.api.response.LogisticsAddressSearchResponse;
import com.taobao.api.response.RefundMessagesGetResponse;
import com.taobao.api.response.RefundRefuseResponse;
import com.taobao.api.response.RpRefundReviewResponse;
import com.taobao.api.response.RpRefundsAgreeResponse;
import com.taobao.api.response.RpReturngoodsAgreeResponse;
import com.taobao.api.response.RpReturngoodsRefuseResponse;

@Service("api-offSale")
public class RefundApplyServiceImpl implements RefundApplyService {

	@Autowired
	private RefundApplyDao refundApplyDao;

	@Autowired
	private RefundCheckInfoDao refundCheckInfoDao;

	@Autowired
	private RefundCommentDao refundCommentDao;
	
	@Autowired
	private RefundAddressDao refundAddressDao;

	@Autowired
	private ShoppDao shoppDao;

	@Autowired
	private ShopDao shopDao;
	
	@Autowired
	private ChannelDao channelDao;
	
	@Autowired
	private ShopStockDao shopStockDao;

	@Autowired
	private ViewRefundApplyDao viewRefundApplyDao;

	@Autowired
	private TradesInfoDao tradesInfoDao;

	@Autowired
	private TradesOrderDao tradesOrderDao;
	@Autowired
	private TradesInfoService tradesInfoService;

	@Autowired
	public OrderLogDao orderLogDao;
	
	@Autowired
	public ShoppDetailDao shoppDetailDao;
	
	@Autowired
	private ProductService productService;
	
	@Autowired
	public SpuDao spuDao;

	@Override
	public Page<ViewRefundApplyWrap> getRefundApplysByCondition(Condition condition, String type) {
		
		//判断入参是否符合规范
		if (!RefundParams.TYPE_REFUND.equals(type) && !RefundParams.TYPE_REJECTED_CHANGE.equals(type))
		{
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "type参数取值不正确");
		}
		
		if (condition == null)
		{
			condition = new Condition();
		}
		
		//设置企业编码
		condition.setEnterpriseCode(ContextHelper.getCurrentLoginInfo().getEnterprise().getEnterpriseCode());
		
		//获取退款/退换货 信息列表(分页)
		Page<Map<String, Object>> page = viewRefundApplyDao.getTidPage(condition, type);
		
		
		Page<ViewRefundApplyWrap> resultPage = new Page<>();
		resultPage.setPageNumber(page.getPageNumber());
		resultPage.setOffset(page.getOffset());
		resultPage.setPageSize(page.getPageSize());
		resultPage.setTotalItems(page.getTotalItems());
		resultPage.setTotalPages(page.getTotalPages());
		if (page == null || page.getItems() == null || page.getItems().isEmpty()) {
			return resultPage;
		}
		List<Map<String, Object>> list = page.getItems();
		List<ViewRefundApplyWrap> wrapList = new ArrayList<>();
		String outSkuId = condition.getOuterSkuId();
		String title = condition.getTitle();
		for (Map<String, Object> map : list) {
			String tid = (String) map.get("tid");
			String afterSaleType = (String) map.get("after_sale_type");
			List<ViewRefundApply> temp = viewRefundApplyDao.getViewRefundApplyByTid(tid, afterSaleType,outSkuId,title);
			if (type.equals(RefundParams.TYPE_REJECTED_CHANGE)) {
				for (ViewRefundApply v : temp) {
					if (v.getAfterSaleType().equals(RefundParams.AFTER_SALE_TYPE_REFUND_CHANGE_GOODS)) {
						if (v.getShoppId() != null) {
							v.setShopp(shoppDao.select(v.getShoppId()));
						}
					}
				}
			}
			ViewRefundApplyWrap wrap = new ViewRefundApplyWrap();
			wrap.setBuyerNick(temp.get(0).getBuyerNick());
			wrap.setRefundApplyList(temp);
			wrap.setShopName(temp.get(0).getShopName());
			wrap.setTid(tid);
			wrap.setTradesCreated(temp.get(0).getTradesCreated());
			wrap.setAfterSaleType(temp.get(0).getAfterSaleType());
			wrapList.add(wrap);
		}
		resultPage.setItems(wrapList);
		return resultPage;
	}

	@Override
	public RefundApply getRefundApply(RefundApply refundApply) {
		Assert.notNull(refundApply.getRefundId(), "退款申请单号");
		RefundApply apply = refundApplyDao.select(refundApply.getRefundId());
		if (apply != null) {// RefundApplyDetailJob
			RefundComment comment = refundCommentDao.getCommentByRefundId(apply.getRefundId());
			if (comment == null)
				comment = this.getRefundComment(apply);
			apply.setRefundComment(comment);
			apply.setCheckInfo(refundCheckInfoDao.getCheckInfoByRefundId(apply.getRefundId()));
			String oid = apply.getOid();
			if (oid != null && !"".equals(oid)) {
				TradesOrder dto = new TradesOrder();
				dto.setOid(oid);
				apply.setTradesOrder(tradesOrderDao.getTradesOrder(dto));
				TradesInfo info = tradesInfoDao.select(apply.getTid());
				Shop shop = shopDao.select(info.getShopId());
				apply.setShop(shop);
			}
		/**
		 * 只有退款情况下才设置ordGoodStatus 值
		 * 查询该订单是否已经审单并审单通过
		 * ordGoodStatus:1未发货(销售单还未审单完成)，2发货中(需要跟仓库发货人员确认是否已经线下发货) ,3已经发货(运单号已经回传至天猫)
		 */
			if("REFUND_MONEY".equals(apply.getAfterSaleType()))
			{
				List<Map<String,Object>> sppList = shopDao.queryForList("select distinct spp.status from t_shopp spp join t_shopp_detail sppd on spp.shopp_id = sppd.shopp_id where sppd.tid = ?", apply.getTid());
				if(null != sppList && sppList.size() > 0)
				{
					for(Map<String,Object> map: sppList)
					{
						//ALREADY_SEND_GOODS 已经发货 
						if("ALREADY_SEND_GOODS".equals(map.get("status")))
						{
							apply.setOrdGoodStatus("3");
							break;
						}
						//WAIT_SEND_GOODS,FAIL_SEND_GOODS:已经进入打单发货界面
						else if("WAIT_SEND_GOODS".equals(map.get("status")) || "FAIL_SEND_GOODS".equals(map.get("status")))
						{
							apply.setOrdGoodStatus("2");
							break;
						}
						else
						{
							continue;
						}
					}
				}
				else
				{
					apply.setOrdGoodStatus("1");
				}
			}
		}
		return apply;
	}

	private RefundComment getRefundComment(RefundApply apply) {
		TradesInfo info = tradesInfoDao.select(apply.getTid());
		Shop shop = shopDao.select(info.getShopId());
		String jsonStr = shop.getRuleInfo();
		String proxUrl = shop.getProxyURL();
		Map<String, String> shopMap = JsonUtil.parse(jsonStr);
		shopMap.put("proxUrl", proxUrl);
		RefundMessagesGetResponse refundMsg = null;
		try {
			refundMsg = RefundApplyDetailJob.getRefundMessages(shopMap, Long.valueOf(apply.getRefundId()),
					apply.getRefundPhase());
		} catch (Exception e) {
			return null;
		}
		if (refundMsg == null)
			return null;
		if (refundMsg.getRefundMessages() != null && !refundMsg.getRefundMessages().isEmpty()) {
			List<RefundComment> commentList = new ArrayList<>();
			for (RefundMessage msg : refundMsg.getRefundMessages()) {
				RefundComment comment = new RefundComment();
				ReflectUtil.refundMessageValueChanger(msg, comment);
				RefundComment comnent = refundCommentDao.getCommentByRefundId(String.valueOf(msg.getRefundId()));
				if (comnent == null)
					commentList.add(comment);
			}
			refundCommentDao.insert(commentList);
		}
		return refundCommentDao.getCommentByRefundId(apply.getRefundId());
	}

	@Override
	@Transactional
	public void doVerify(RefundApply refundApply) {
		Assert.notNull(refundApply, "审核对象");
		Assert.notNull(refundApply.getRefundId(), "审核单号");
		Assert.notNull(refundApply.getProcessStatus(), "处理状态");
		
		//获取当前企业是否有链接外部ERP系统
		String outMCode = ContextHelper.getCurrentLoginInfo().getEnterprise().getOutMallCode();
				
		//ERP 链接不为空则调用erp系统通知此订单tid 需要退货
		if(!StringUtils.isEmpty(outMCode))
		{
			// more
		}
		
		//获取售后单信息
		RefundApply apply = refundApplyDao.select(refundApply.getRefundId());
		if (apply == null)
		{
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "此售后单不存在");
		}
		// 把更新内容赋值到目标对象上
		ReflectUtil.reflect(refundApply, apply);
		Boolean status = false;
		
		// 交易订单的状态也要更改
		TradesInfo info = tradesInfoDao.select(apply.getTid());
		
		//店铺信息
		Shop shop = shopDao.select(info.getShopId());
		
		//客服拒绝退(货)款
		if (RefundParams.PROCESS_STATUS_DENY.equals(refundApply.getProcessStatus())) 
		{
			
			Assert.notNull(refundApply.getCwRefuseProof(), "拒绝凭证");
			apply.setIsNoticeBuyer(2);
			apply.setProcessStatus(RefundParams.PROCESS_STATUS_DENY);
			apply.setStatus(RefundParams.ORDER_STATUS_SELLER_REFUSE_BUYER);
			//设置备注
			apply.setCwRefuseRemark(refundApply.getSellerRemark());
			
			//调用天猫接口并告知客服操作结果 拒绝/同意  退款
			status = this.tmallRefuseRefundApply(apply);
			
			//以afterSaleType字段进行逻辑判断 afterSaleType = ‘退货’
			if (RefundParams.AFTER_SALE_TYPE_REFUND_REFUND_GOODS.equals(refundApply.getAfterSaleType())) 
			{
				// 生成订单处理日志
				orderLogDao.insert(tradesInfoService.createOrderLog(apply.getTid(), "1",ContextHelper.getCurrentLoginInfo().getAdminId(), "客服拒绝退货", BusiType.ORDER_REFUND_GOODS.name(),"成功", apply.getCwRefuseRemark()));
				//以afterSaleType字段进行逻辑判断 afterSaleType = ‘退款’
			} 
			else if (RefundParams.AFTER_SALE_TYPE_REFUND_MONEY.equals(refundApply.getAfterSaleType())) 
			{
				// 生成订单处理日志
				orderLogDao.insert(tradesInfoService.createOrderLog(apply.getTid(), "1",ContextHelper.getCurrentLoginInfo().getAdminId(), "客服拒绝退款", BusiType.ORDER_REFUND.name(), "成功",apply.getCwRefuseRemark()));
			}
			else
			{
				throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "afterSaleType参数错误！");
			}
		}
		//客服同意退(货)款
		if (RefundParams.PROCESS_STATUS_PROCESS.equals(refundApply.getProcessStatus())) 
		{
			//查询该订单是否存在发货单信息。 若存在则表示已经发货(不需要加库存) 若不存在则表示未发货(需要加库存)
			List<ShoppDetail> spDetailList = shoppDetailDao.selectWhere(" tid = ? ", refundApply.getTid());
			if(null == spDetailList || spDetailList.size() == 0)
			{
				this.s002AddStock(apply,shop,info);
			}
			
			//是否通知买家(0：未通知；1：已通知,同意退款；2：已通知，拒绝退款)
			apply.setIsNoticeBuyer(1);
			apply.setProcessStatus(RefundParams.PROCESS_STATUS_PROCESS);
			
			//退货
			if (RefundParams.AFTER_SALE_TYPE_REFUND_REFUND_GOODS.equals(apply.getAfterSaleType())) 
			{ 
				//------- 修改天猫默认退货地址与仓库所选退货地址一致--------
				this.callTmallRefunAddress(refundApply.getAddressId(), shop);
				
				//是否已通知仓库(0为未通知，1为已通知并同意，2为已通知未同意)
				apply.setIsNoticeStock("1");
				status = this.tmallAgreeRefundGoods(apply);
				info.setRefundGoods(true);// 已退货
				apply.setStatus(RefundParams.ORDER_STATUS_WAIT_BUYER_RETURN_GOODS);
				// 生成订单处理日志
				orderLogDao.insert(tradesInfoService.createOrderLog(apply.getTid(), "1",
						ContextHelper.getCurrentLoginInfo().getAdminId(), "客服同意退货", BusiType.ORDER_REFUND_GOODS.name(),
						"成功", apply.getSellerRemark()));
			}
			//退款
			else if (RefundParams.AFTER_SALE_TYPE_REFUND_MONEY.equals(refundApply.getAfterSaleType())) 
			{
				apply.setIsNoticeRefund("1");
				if(null != refundApply.getSellerRemark())
				{
					apply.setOptRemark(refundApply.getSellerRemark());	
				}
				
				status = this.tmallAgreeRefundApply(apply);
				info.setRefund(true);// 已退款
				apply.setStatus(RefundParams.ORDER_STATUS_WAIT_SELLER_AGREE);

				// 生成订单处理日志
				orderLogDao.insert(tradesInfoService.createOrderLog(apply.getTid(), "1",
						ContextHelper.getCurrentLoginInfo().getAdminId(), "客服同意退款", BusiType.ORDER_REFUND.name(), "成功",
						apply.getOptRemark()));
			}
			else
			{
				throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "afterSaleType参数错误！");
			}
			if (status)
			{
				apply.setStatus(RefundParams.ORDER_STATUS_WAIT_BUYER_RETURN_GOODS);
			}
			tradesInfoDao.update(info);
		}
		if (!status)
		{
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "同步淘宝操作失败！");
		}
		refundApplyDao.update(apply);

	}
	
	/**
	 * 将选择的退货地址设置成默认地址，并调用天猫接口修改天猫退货默认地址
	 * @param addressId
	 */
	public void callTmallRefunAddress(Long addressId,Shop shop)
	{
		RefundAddress refundADS =  refundAddressDao.select(addressId);
		//将该企业下所有退货地址设置成非默认
		Object [] args = {shop.getShopId(),ContextHelper.getCurrentLoginInfo().getEnterpriseCode()};
		refundAddressDao.executeUpdate("update t_refund_address set is_default = 0 where shop_id = ? and enterprise_code = ? ", args);
		
		if(null != refundADS)
		{
			refundADS.setDefaults(true);
		}
		Map<String, String> publicParams = JsonUtil.parse(shop.getRuleInfo());
		publicParams.put("url", shop.getProxyURL());
		//获取调用天猫类对象
		IThirdPartyService client = ThirdPartyFactory.getTmallClient();
		//修改天猫退货默认地址
		boolean flag = client.updateRefundAddressInfo(publicParams, refundADS);
		if(flag)
		{
			refundAddressDao.update(refundADS);
		}
	}
	
	
	/**
	 * 根据 验收结论字段判断进行逻辑处理 ：S002 完整（可重售） //允许入库
	 * 更新店铺库存，生成入库记录
	 * @param apply
	 * @param refundCheckInfo
	 * @param shop
	 * @param info
	 */
	public void s002AddStock(RefundApply apply,Shop shop,TradesInfo info)
	{
		Assert.notNull(apply.getOuterSkuId(), "商品编码");
		Assert.notNull(apply.getGoodsNum(), "商品数量");
		//回退到店铺仓
		String enterpriseCode = ContextHelper.getCurrentLoginInfo().getEnterprise().getEnterpriseCode();
		ShopStock sStock = shopStockDao.getByShopIdSkuIdEpCode(apply.getOuterSkuId(), enterpriseCode, info.getShopId());
		if(null == sStock)
		{
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "店铺库存数据为空");
		}
		sStock.setStock(sStock.getStock() + apply.getGoodsNum());
		
		//生成入库记录
		StockRecord record = new StockRecord();
		record.setRecordType(StaticParam.D_STOCK_TYPE_IN);
		record.setCreateUserId(ContextHelper.getCurrentLoginInfo().getAdminId());
		record.setCreateTime(new Timestamp(System.currentTimeMillis()));
		if(shop != null)
		{
			record.setRelevantStoreId(shop.getShopId());
			record.setOperateStoreId(shop.getShopId());
			Channel channel = channelDao.getChannelByChannelCode(shop.getChannelCode());
			if(channel != null)
			{
				record.setChannelCode(channel.getChannelCode());
				record.setOperateChannelCode(channel.getChannelCode());
				record.setRelevantChannelCode(channel.getChannelCode());//关联仓库所属渠道
			}
		}
		
		record.setStockType(StaticParam.STORE_IN_OF_REFUND_GOODS);
		record.setRemark(apply.getCwRefuseRemark());
		record.setEnterpriseCode(ContextHelper.getCurrentLoginInfo().getEnterprise().getEnterpriseCode());
		List<StockDetail> tempList = new ArrayList<>();
		StockDetail detail = new StockDetail();
		detail.setSpuId(sStock.getSpuId());
		detail.setSkuId(sStock.getSkuId());
		detail.setIncoming(apply.getGoodsNum());
		detail.setPrice(sStock.getPrice());
		detail.setStatus(StaticParam.IN_STATUS_DONE);
		tempList.add(detail);
		record.setStockDetailList(tempList);
		//同步天猫库存(增加回退商品的库存)
		Map<String,Object> params = new HashMap<>();
		params.put("shopStock", sStock);
		params.put("stockDetail", detail);
		try 
		{
			this.updateOutStoreStock(params);
		}
		catch (Exception e) 
		{
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "更新外部商城库存失败！");
		}
		//更新库存数量
		shopStockDao.update(sStock);
		
		//生成入库单数据
		productService.insertStockRecord(record, StaticParam.IN_FLAG);
	}

	/**
	 * 卖家拒绝退货
	 * 
	 * @param refundApply
	 * @return
	 * @throws Exception
	 */
	private Boolean tmallRefuseRefundGoods(RefundApply refundApply) {
		RefundApply temp = refundApplyDao.select(refundApply.getRefundId());
		TradesInfo info = tradesInfoDao.select(temp.getTid());
		Map<String, String> shopMap = this.getShopMap(info.getShopId());
		TaobaoClient client = new DefaultTaobaoClient(shopMap.get(ShopConnAttr.SHOP_CONN_PROXURL),
				shopMap.get(ShopConnAttr.SHOP_CONN_APPKEY), shopMap.get(ShopConnAttr.SHOP_CONN_SECRET));
		RpReturngoodsRefuseRequest req = new RpReturngoodsRefuseRequest();
		req.setRefundId(Long.valueOf(refundApply.getRefundId()));
		req.setRefundPhase(refundApply.getRefundPhase());
		req.setRefundVersion(Long.valueOf(refundApply.getRefundVersion()));
		if (refundApply.getCwRefuseProof() != null && !"".equals(refundApply.getCwRefuseProof())) 
		{
			InputStream ins = this.getProofFile(refundApply.getCwRefuseProof());
			if (ins != null)
			{
				req.setRefuseProof(new FileItem(refundApply.getCwRefuseProof(), ins));
			}
		}
		RpReturngoodsRefuseResponse rsp = null;
		try 
		{
			rsp = client.execute(req, shopMap.get(ShopConnAttr.SHOP_CONN_APPSESSION));
		}
		catch (ApiException e) 
		{
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "同步淘宝操作失败！");
		}
		if (rsp.getSubMsg() != null)
		{
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + rsp.getErrorCode() + ","
					+ rsp.getMsg() + ";subCode:" + rsp.getSubCode() + "," + rsp.getSubMsg());
		}
		if (rsp.getMsg() != null)
		{
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + rsp.getErrorCode() + ","
					+ rsp.getMsg() + ";subCode:" + rsp.getSubCode() + "," + rsp.getMsg());
		}
		return rsp.isSuccess();
	}

	/**
	 * 卖家同意退货
	 * 
	 * @param refundApply
	 * @return
	 * @throws Exception
	 */
	private Boolean tmallAgreeRefundGoods(RefundApply refundApply) {
		RefundApply temp = refundApplyDao.select(refundApply.getRefundId());
		TradesInfo info = tradesInfoDao.select(temp.getTid());
		Object[] args = new Object[]{ContextHelper.getCurrentLoginInfo().getEnterpriseCode(),info.getShopId()};
		List<RefundAddress> refundAddressList = refundAddressDao.selectWhere(" enterprise_code = ? and shop_id = ?  and is_default = 1 ", args);
		if(null == refundAddressList || refundAddressList.size() == 0)
		{
			refundAddressList = refundAddressDao.selectWhere(" enterprise_code = ? and shop_id = ? ", args);
		}
		RefundAddress address = refundAddressList.get(0);
		if(null == address)
		{
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "企业地址信息不全");
		}
		Map<String, String> shopMap = this.getShopMap(info.getShopId());
		TaobaoClient client = new DefaultTaobaoClient(shopMap.get(ShopConnAttr.SHOP_CONN_PROXURL),
				shopMap.get(ShopConnAttr.SHOP_CONN_APPKEY), shopMap.get(ShopConnAttr.SHOP_CONN_SECRET));
		RpReturngoodsAgreeRequest req = new RpReturngoodsAgreeRequest();
		req.setRefundId(Long.valueOf(refundApply.getRefundId()));
		//req.setName(address.getName());
		// 省+市+区(县) +详细地址
		//req.setAddress(address.getReceiverState() + address.getReceiverCity() + address.getReceiverDistrict() + address.getReceiverAddress());
		//req.setPost(address.getPostCode());
		//req.setTel(temp.getSellerTel());
		//req.setMobile(address.getPhone());
		req.setRemark(refundApply.getSellerRemark());
		req.setRefundPhase(refundApply.getRefundPhase() == null ? null : refundApply.getRefundPhase());
		req.setRefundVersion(
				refundApply.getRefundVersion() == null ? null : Long.valueOf(refundApply.getRefundVersion()));
		//Long sellerAddressId = this.getTaobaoSellerAddressId(shopMap);
		//if (sellerAddressId == null)
		//	throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "调用天猫卖家同意退货接口失败！");
		req.setSellerAddressId(refundApply.getAddressId());
		RpReturngoodsAgreeResponse rsp = null;
		try {
			rsp = client.execute(req, shopMap.get(ShopConnAttr.SHOP_CONN_APPSESSION));
		} catch (ApiException e) {
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "调用天猫卖家同意退货接口报错");
		}
		if (rsp.getSubMsg() != null)
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + rsp.getErrorCode() + ","
					+ rsp.getMsg() + ";subCode:" + rsp.getSubCode() + "," + rsp.getSubMsg());
		if (rsp.getMsg() != null)
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + rsp.getErrorCode() + ","
					+ rsp.getMsg() + ";subCode:" + rsp.getSubCode() + "," + rsp.getMsg());
		return rsp.getIsSuccess();
	}

	@SuppressWarnings("unused")
	private Long getTaobaoSellerAddressId(Map<String, String> shopMap) {
		TaobaoClient client = new DefaultTaobaoClient(shopMap.get(ShopConnAttr.SHOP_CONN_PROXURL),
				shopMap.get(ShopConnAttr.SHOP_CONN_APPKEY), shopMap.get(ShopConnAttr.SHOP_CONN_SECRET));
		LogisticsAddressSearchRequest req = new LogisticsAddressSearchRequest();
		req.setRdef("cancel_def");
		LogisticsAddressSearchResponse rsp = null;
		try {
			rsp = client.execute(req, shopMap.get(ShopConnAttr.SHOP_CONN_APPSESSION));
		} catch (ApiException e) {
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "同步淘宝操作失败！");
		}
		if (rsp.getSubMsg() != null)
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + rsp.getErrorCode() + ","
					+ rsp.getMsg() + ";subCode:" + rsp.getSubCode() + "," + rsp.getSubMsg());
		if (rsp.getMsg() != null)
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + rsp.getErrorCode() + ","
					+ rsp.getMsg() + ";subCode:" + rsp.getSubCode() + "," + rsp.getMsg());
		List<AddressResult> list = rsp.getAddresses();
		if (list == null || list.isEmpty()) {
			req.setRdef("cancel_def");
			try {
				rsp = client.execute(req, shopMap.get(ShopConnAttr.SHOP_CONN_APPSESSION));
			} catch (ApiException e) {
				throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "同步淘宝操作失败！");
			}
			if (rsp.getSubMsg() != null)
				throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + rsp.getErrorCode() + ","
						+ rsp.getMsg() + ";subCode:" + rsp.getSubCode() + "," + rsp.getSubMsg());
			if (rsp.getMsg() != null)
				throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + rsp.getErrorCode() + ","
						+ rsp.getMsg() + ";subCode:" + rsp.getSubCode() + "," + rsp.getMsg());
			list = rsp.getAddresses();
			if (list == null || list.isEmpty())
				return null;
		}
		return list.get(0).getContactId();
	}

	/**
	 * 卖家同意退款
	 * 
	 * @param refundApply
	 * @return
	 * @throws ApiException
	 */
	@Override
	public Boolean tmallAgreeRefundApply(RefundApply refundApply) {
		RefundApply temp = refundApplyDao.select(refundApply.getRefundId());
		TradesInfo info = tradesInfoDao.select(temp.getTid());
		Map<String, String> shopMap = this.getShopMap(info.getShopId());
		TaobaoClient client = new DefaultTaobaoClient(shopMap.get(ShopConnAttr.SHOP_CONN_PROXURL),
				shopMap.get(ShopConnAttr.SHOP_CONN_APPKEY), shopMap.get(ShopConnAttr.SHOP_CONN_SECRET));
		RpRefundReviewRequest req = new RpRefundReviewRequest();
		req.setRefundId(Long.valueOf(temp.getRefundId()));
		req.setOperator(ContextHelper.getCurrentLoginInfo().getAccount());
		req.setRefundPhase(temp.getRefundPhase());
		req.setRefundVersion(Long.valueOf(temp.getRefundVersion()));
		req.setResult(true);
		req.setMessage(refundApply.getOptRemark() == null ? null : refundApply.getOptRemark());
		RpRefundReviewResponse response = null;
		try {
			response = client.execute(req, shopMap.get(ShopConnAttr.SHOP_CONN_APPSESSION));
		} catch (ApiException e) {
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "调用天猫卖家同意退款接口失败");
		}
		if (response.getSubMsg() != null)
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + response.getErrorCode() + ","
					+ response.getMsg() + ";subCode:" + response.getSubCode() + "," + response.getSubMsg());
		if (response.getMsg() != null)
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + response.getErrorCode() + ","
					+ response.getMsg() + ";subCode:" + response.getSubCode() + "," + response.getMsg());
		return response.getIsSuccess();
	}

	/**
	 * 卖家拒绝退款
	 * 
	 * @param refundApply
	 * @return
	 * @throws Exception
	 */
	private Boolean tmallRefuseRefundApply(RefundApply refundApply) 
	{
		RefundRefuseResponse rsp = null;
		ViewRefundApply vApply = viewRefundApplyDao.select(refundApply.getRefundId());
		refundCheckInfoDao.getCheckInfoByRefundId(refundApply.getRefundId());
		Map<String, String> shopMap = this.getShopMap(vApply.getShopId());
		
		try 
		{
			TaobaoClient client = new DefaultTaobaoClient(shopMap.get(ShopConnAttr.SHOP_CONN_PROXURL),
					shopMap.get(ShopConnAttr.SHOP_CONN_APPKEY), shopMap.get(ShopConnAttr.SHOP_CONN_SECRET));
			RefundRefuseRequest req = new RefundRefuseRequest();
			req.setRefundId(Long.valueOf(refundApply.getRefundId()));
			req.setRefuseMessage(refundApply.getCwRefuseRemark() == null
					? (refundApply.getOptRemark() == null ? null : refundApply.getOptRemark())
					: refundApply.getCwRefuseRemark());
			req.setTid(Long.valueOf(vApply.getTid()));
			req.setOid(Long.valueOf(refundApply.getOid()));
			if (refundApply.getCwRefuseProof() != null && !refundApply.getCwRefuseProof().equals("")) 
			{
				InputStream ins = this.getProofFile(refundApply.getCwRefuseProof());
				if (ins != null)
					req.setRefuseProof(new FileItem(refundApply.getCwRefuseProof(), ins));
			}
			req.setRefundPhase(refundApply.getRefundPhase());
			req.setRefundVersion(Long.valueOf(refundApply.getRefundVersion()));
			rsp = client.execute(req, shopMap.get(ShopConnAttr.SHOP_CONN_APPSESSION));
			if (rsp.getSubMsg() != null)
			{
				throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + rsp.getErrorCode() + "," + rsp.getMsg() + ";subCode:" + rsp.getSubCode() + "," + rsp.getSubMsg());
			}
			if (rsp.getMsg() != null)
			{
				throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + rsp.getErrorCode() + "," + rsp.getMsg() + ";subCode:" + rsp.getSubCode() + "," + rsp.getMsg());
			}
		}
		catch (ApiException e) 
		{
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "调用天猫卖家拒绝退款 失败");
		}
		
		return rsp.getIsSuccess();
	}

	private InputStream getProofFile(String fileName) {
		InputStream inputStream = null;
		HttpURLConnection httpURLConnection = null;
		String path = ContextHelper.getBean("serviceConfig", ServiceConfig.class).getFileUrl() + "image/product/base/"
				+ fileName;
		URL url;
		try {
			url = new URL(path);
			httpURLConnection = (HttpURLConnection) url.openConnection();
			// 设置网络连接超时时间
			httpURLConnection.setConnectTimeout(3000);
			// 设置应用程序要从网络连接读取数据
			httpURLConnection.setDoInput(true);
			httpURLConnection.setRequestMethod("GET");
			int responseCode = httpURLConnection.getResponseCode();
			if (responseCode == 200) {
				// 从服务器返回一个输入流
				inputStream = httpURLConnection.getInputStream();
			}
		} catch (Exception e) {
			inputStream = null;
		}
		return inputStream;
	}

	@Override
	public RefundApply getEndRefundPage(RefundApply refundApply) {
		return this.getRefundApply(refundApply);
	}

	@Override
	public void doRefundNotice(RefundApply refundApply) {
		Assert.notNull(refundApply, "申请单号");
		Assert.notNull(refundApply.getRefundId(), "申请单号");
		RefundApply apply = refundApplyDao.select(refundApply.getRefundId());
		if (apply == null)
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "没有权限操作此对象");
		// 把更新内容赋值到目标对象上
		apply.setIsNoticeRefund("1");
		refundApplyDao.update(apply);
	}

	@Override
	@Transactional
	public void doEndRefund(RefundApply refundApply) {
		Assert.notNull(refundApply, "申请单号");
		Assert.notNull(refundApply.getRefundId(), "申请单号");
		RefundApply apply = refundApplyDao.select(refundApply.getRefundId());
		if (apply == null)
		{
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "没有权限操作此对象");
		}
		if (!apply.getAfterSaleType().equals(RefundParams.AFTER_SALE_TYPE_REFUND_MONEY)) {
			Assert.notNull(refundApply.getCheckId(), "仓库验货单号");
			RefundCheckInfo checkedInfo = refundCheckInfoDao.select(refundApply.getCheckId());
			if (checkedInfo == null)
			{
				throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "尚无仓库验货记录,不能进行此操作");
			}
			if (checkedInfo.getCheckResult().contains(RefundParams.CHECK_RESULT_S001)
					|| checkedInfo.getCheckResult().contains(RefundParams.CHECK_RESULT_S002)
					|| checkedInfo.getCheckResult().contains(RefundParams.CHECK_RESULT_S003)) {
				apply.setIsNoticeBuyer(1);
				apply.setProcessStatus(RefundParams.PROCESS_STATUS_SUCCESS);
				apply.setFeedbackStatus(RefundParams.FEEDBACK_STATUS_ACCEPT);
				if (checkedInfo.getCheckResult().contains(RefundParams.CHECK_RESULT_S002)) {// 已在仓库验货时进行操作
					// 回退到店铺仓
					// TradesInfo info = tradesInfoDao.select(apply.getTid());
					// String enterpriseCode =
					// ContextHelper.getCurrentLoginInfo().getEnterprise().getEnterpriseCode();
					// ShopStock sStock =
					// shopStockDao.getByShopIdSkuIdEpCode(Integer.valueOf(checkedInfo.getOuterSkuId()),
					// enterpriseCode, info.getShopId());
					// sStock.setStock(sStock.getStock() +
					// checkedInfo.getRealAmount());
					// shopStockDao.update(sStock);
					//
					// //生成入库记录
					// Shop shop = shopDao.select(info.getShopId());
					// StockRecord record = new StockRecord();
					// record.setRecordType(StaticParam.D_STOCK_TYPE_IN);
					// record.setCreateUserId(ContextHelper.getCurrentLoginInfo().getAdminId());
					// record.setCreateTime(new
					// Timestamp(System.currentTimeMillis()));
					// record.setRelevantStore(shop.getName());
					// record.setOperateStore(shop.getName());
					// record.setStockType(StaticParam.IN_TYPE_FALLBACK);
					// record.setEnterpriseCode(ContextHelper.getCurrentLoginInfo().getEnterprise().getEnterpriseCode());
					// List<StockDetail> tempList = new ArrayList<>();
					// StockDetail detail = new StockDetail();
					// Sku sku = skuDao.select(sStock.getSkuId());
					// detail.setSpuId(sku.getSpuId());
					// detail.setSkuId(sku.getSkuId());
					// detail.setIncoming(checkedInfo.getRealAmount());
					// detail.setPrice(sku.getPrice());
					// detail.setStatus(StaticParam.IN_STATUS_DONE);
					// tempList.add(detail);
					// record.setStockDetailList(tempList);
					// productService.insertStockRecord(record,
					// StaticParam.IN_FLAG);
					//
					// //同步天猫库存(增加回退商品的库存)
					// Map<String,Object> params = new HashMap<>();
					// params.put("shopStock", sStock);
					// params.put("stockDetail", detail);
					// try {
					// this.updateOutStoreStock(params);
					// } catch (Exception e) {
					// throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE,
					// "更新外部商城库存失败！");
					// }
				}
			}
			else 
			{
				apply.setIsNoticeBuyer(2);
				apply.setProcessStatus(RefundParams.PROCESS_STATUS_DENY);
				apply.setFeedbackStatus(RefundParams.FEEDBACK_STATUS_DENY);
			}
			if (RefundParams.AFTER_SALE_TYPE_REFUND_REFUND_GOODS.equals(apply.getAfterSaleType())) 
			{
				if (RefundParams.PROCESS_STATUS_SUCCESS.equals(apply.getProcessStatus())
						&& RefundParams.REFUND_RESULT_ACCEPT.equals(apply.getRefundResult()))
				{
					apply.setProcessStatus(RefundParams.PROCESS_STATUS_SUCCESS);
				}
				if (RefundParams.PROCESS_STATUS_SUCCESS.equals(apply.getProcessStatus())
						&& RefundParams.REFUND_RESULT_DENY.equals(apply.getRefundResult()))
				{
					apply.setProcessStatus(RefundParams.PROCESS_STATUS_DENY);
				}
			}
			// if(!checkedInfo.getCheckResult().contains(RefundParams.CHECK_RESULT_S002)){
			// this.doRefuseRemit(apply);
			// }
		} else {
			if (apply.getRefundResult().equals(RefundParams.REFUND_RESULT_ACCEPT))
			{
				apply.setProcessStatus(RefundParams.PROCESS_STATUS_SUCCESS);
			}
			if (apply.getRefundResult().equals(RefundParams.REFUND_RESULT_DENY))
			{
				apply.setProcessStatus(RefundParams.PROCESS_STATUS_DENY);
			}
		}
		apply.setStatus(RefundParams.ORDER_STATUS_CLOSED);
		Object [] args = {apply.getTid(),apply.getSkuStr().substring(0, 14)};
		List<TradesOrder> orderList = tradesOrderDao.selectWhere(" tid = ? and sku_id = ? ", args);
		if(null != orderList && orderList.size() > 0)
		{
			tradesOrderDao.executeUpdate("update t_trades_order set is_after_sale = 1 where order_id = ? and is_after_sale != 2", orderList.get(0).getOrderId());
		}
		refundApplyDao.update(apply);

		// 更新订单状态
		TradesInfo info = tradesInfoDao.select(apply.getTid());
		info.setStatus(TradesStatus.TRADE_CLOSED.name());
		tradesInfoDao.update(info);
		

		// 生成订单处理日志
		if (apply.getAfterSaleType().equals(RefundParams.AFTER_SALE_TYPE_REFUND_MONEY)) {
			orderLogDao.insert(tradesInfoService.createOrderLog(apply.getTid(), "1",
					ContextHelper.getCurrentLoginInfo().getAdminId(), "客服结束退款", BusiType.ORDER_REFUND.name(), "成功",
					"无"));
		} else {
			orderLogDao.insert(tradesInfoService.createOrderLog(apply.getTid(), "1",
					ContextHelper.getCurrentLoginInfo().getAdminId(), "客服结束退货", BusiType.ORDER_REFUND_GOODS.name(),
					"成功", "无"));
		}
	}

	@Override
	public void updateOutStoreStock(Map<String, Object> params) throws Exception {
		ShopStock shopStock = (ShopStock) params.get("shopStock");
		Shop shop = shopDao.select(shopStock.getShopId());
		Map<String, String> publicParams = JsonUtil.parse(shop.getRuleInfo());
		publicParams.put("url", shop.getProxyURL());
		StockDetail detail = (StockDetail) params.get("stockDetail");
		Map<String, String> bizParams = new HashMap<>();
		bizParams.put("numIid", shopStock.getChannelSpu());
		bizParams.put("outerId", String.valueOf(detail.getSkuId()));
		bizParams.put("quantity", String.valueOf(detail.getIncoming()));
		IThirdPartyService client = ThirdPartyFactory.getTmallClient();
		client.updateStock(publicParams, bizParams);
	}

	@Override
	@Transactional
	public void doGoodsValidate(RefundCheckInfo checkedInfo) {
		Assert.notNull(checkedInfo, "验货信息");
		Assert.notNull(checkedInfo.getRefundId(), "退款申请单号");
		checkedInfo.setCreatedAt(new Timestamp(System.currentTimeMillis()));
		checkedInfo.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
		checkedInfo.setOptUserId(ContextHelper.getCurrentLoginInfo().getAdminId().toString());
		refundCheckInfoDao.insert(checkedInfo);
		RefundApply apply = refundApplyDao.select(checkedInfo.getRefundId());
		if (checkedInfo.getCheckResult().substring(0, 4).equals(RefundParams.CHECK_RESULT_S002)
				|| checkedInfo.getCheckResult().substring(0, 4).equals(RefundParams.CHECK_RESULT_S003))
			apply.setFeedbackStatus(RefundParams.FEEDBACK_STATUS_ACCEPT);
		else
			apply.setFeedbackStatus(RefundParams.FEEDBACK_STATUS_DENY);
		apply.setFeedbackTime(new Timestamp(System.currentTimeMillis()));
		refundApplyDao.update(apply);
	}

	@Override
	public Map<String, String> getCheckResultMap() {
		return RefundParams.CHECK_RESULT_MAP;
	}

	@Override
	public void doVerifyChangeGoods(RefundApply refundApply) {
		Assert.notNull(refundApply, "换货申请");
		Assert.notNull(refundApply.getTid(), "交易单号");
		Assert.notNull(refundApply.getOid(), "子交易单号");
		Assert.notNull(refundApply.getRefundNums(), "换货数量");
		Assert.notNull(refundApply.getChangeSkuCode(), "换货商品编码");
		Assert.notNull(refundApply.getChangeSkuName(), "换货商品名称");
		TradesOrder dto = new TradesOrder();
		dto.setTid(refundApply.getTid());
		dto.setOid(refundApply.getOid());
		
		//设置商品数量
		refundApply.setGoodsNum(refundApply.getNum());
		
		TradesInfo info = tradesInfoDao.select(refundApply.getTid());
		TradesOrder order = tradesOrderDao.getTradesOrder(dto);
		String enterpriseCode = ContextHelper.getCurrentLoginInfo().getEnterprise().getEnterpriseCode();
		Integer skuId = null;
		if(!StringUtils.isEmpty(refundApply.getChangeSkuCode()))
		{
			skuId = Integer.parseInt(refundApply.getChangeSkuCode());
		}
		else
		{
			skuId = refundApply.getOuterSkuId();
		}
		ShopStock sStock = shopStockDao.getByShopIdSkuIdEpCode(skuId, enterpriseCode, info.getShopId());
		if (order == null)
		{
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "订单不存在！");
		}
		if(null != sStock)
		{
			refundApply.setSkuStr(sStock.getChannelSku() + "|");	
		}
		else
		{
			refundApply.setSkuStr(order.getSkuId() + "|");
		}
		
		refundApply.setCreated(new Timestamp(System.currentTimeMillis()));
		refundApply.setCreatedAt(new Timestamp(System.currentTimeMillis()));
		refundApply.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
		refundApply.setProcessStatus(RefundParams.PROCESS_STATUS_PROCESS);
		refundApply.setStatus(RefundParams.PHASE_TYPE_SELLER_AGREE);
		refundApply.setAfterSaleType(RefundParams.AFTER_SALE_TYPE_REFUND_CHANGE_GOODS);
		synchronized (this) {
			String refundId = this.generateRefundId();
			refundApply.setRefundId(refundId);
			refundApply.setOptUserId(String.valueOf(ContextHelper.getCurrentLoginInfo().getAdminId()));
			refundApply.setFeedbackTime(null);
			refundApply.setFeedbackStatus(null);
			refundApplyDao.insert(refundApply);

			info.setChangeGoods(true);//已换货
			tradesInfoDao.update(info);
			tradesOrderDao.executeUpdate("update t_trades_order set is_after_sale = 2 where order_id = ? ", refundApply.getOrderId());
			
			this.createTradesOrder(refundApply,order,info.getShopId());

			// 生成订单处理日志
			orderLogDao.insert(tradesInfoService.createOrderLog(refundApply.getTid(), "1",
					ContextHelper.getCurrentLoginInfo().getAdminId(), "客服同意换货", BusiType.ORDER_CHANGE_GOODS.name(),
					"成功", refundApply.getDescription()));
		}
	}
	/**
	 * 生成订单明细
	 */
	public void createTradesOrder(RefundApply apply,TradesOrder nOrder,Integer shopId)
	{
		String enterpriseCode = ContextHelper.getCurrentLoginInfo().getEnterprise().getEnterpriseCode();
		ShopStock sStock = shopStockDao.getByShopIdSkuIdEpCode(Integer.valueOf(apply.getChangeSkuCode()), enterpriseCode, shopId);
		nOrder.setOuterSkuId(String.valueOf(sStock.getSkuId()));
		nOrder.setSkuId(String.valueOf(sStock.getChannelSku()));
		nOrder.setNumIid(sStock.getChannelSpu());
		nOrder.setNum(apply.getRefundNums());
		Spu spu = spuDao.select(sStock.getSpuId());
		nOrder.setTitle(spu.getTitle());
		nOrder.setPrice(String.valueOf(sStock.getPrice()));
		nOrder.setStatus(RefundParams.ORDER_STATUS_WAIT_BUYER_CONFIRM_GOODS);
		nOrder.setOrderId(null);
		nOrder.setIsAfterSale(0);
		tradesOrderDao.insert(nOrder);
	}

	/**
	 * 生成换货单号
	 * 
	 * @return
	 */
	private String generateRefundId() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String queryStr = RefundParams.CG_ID_FLAG + sdf.format(new Date());
		Long total = refundApplyDao.getRefundIdStr(queryStr + "%");
		if (total < 9)
			queryStr += "0000" + (total + 1);
		else if (total < 99)
			queryStr += "000" + (total + 1);
		else if (total < 999)
			queryStr += "00" + (total + 1);
		else if (total < 9999)
			queryStr += "0" + (total + 1);
		else
			queryStr += (total + 1);
		return queryStr;
	}

	@Override
	public void doEndChangeGoods(RefundApply refundApply) {
		Assert.notNull(refundApply.getRefundId(), "换货申请单号");
		RefundApply apply = refundApplyDao.select(refundApply.getRefundId());
		if (apply == null)
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "没有权限操作此对象");
		apply.setProcessStatus(RefundParams.PROCESS_STATUS_SUCCESS);
		apply.setStatus(RefundParams.ORDER_STATUS_CLOSED);
		refundApplyDao.update(apply);

		// 更新订单状态
		TradesInfo info = tradesInfoDao.select(apply.getTid());
		info.setStatus(TradesStatus.TRADE_FINISHED.name());
		tradesInfoDao.update(info);

		// 生成订单处理日志
		orderLogDao.insert(
				tradesInfoService.createOrderLog(apply.getTid(), "1", ContextHelper.getCurrentLoginInfo().getAdminId(),
						"客服结束换货", BusiType.ORDER_CHANGE_GOODS.name(), "成功", "无"));
	}

	@Override
	@Transactional
	public void doGoodsChange(String refundId, Shopp shopp) {
		Assert.notNull(refundId, "换货申请单号");
		Assert.notNull(shopp, "发货单信息");
		RefundApply apply = refundApplyDao.select(refundId);
		apply.setStatus(RefundParams.PHASE_TYPE_STOCK_AGREE);
		apply.setProcessStatus(RefundParams.PROCESS_STATUS_PROCESS);
		refundApplyDao.update(apply);
		shopp.setCreateTime(new Timestamp(System.currentTimeMillis()));
		shopp.setCreateUserId(ContextHelper.getCurrentLoginInfo().getAdminId());
		shopp.setShoppType(RefundParams.SHOPP_TYPE_CHANGE_GOODS);
		shopp.setStatus(RefundParams.SHOPP_STATUS_TO_BE_SHIPPED);
		shoppDao.insert(shopp);
	}

	@Override
	public void jobOpen() {
		QuartzJobCommonUtil.build(JobNameParams.SYNC_REFUND_APPLY, JobNameParams.BUSSINESS_GROUP_REFUND,
				JobNameParams.SYNC_REFUND_APPLY_INTERVAL, RefundApplyJob.class);
		QuartzJobCommonUtil.start();
	}

	@Override
	public Page<ViewRefundApplyWrap> getNotRefundApplys(Condition condition) {
		// 未处理
		String processStatus = RefundParams.PROCESS_STATUS_PROCESS;
		if (condition == null) {
			condition = new Condition();
		}
		condition.setEnterpriseCode(ContextHelper.getCurrentLoginInfo().getEnterprise().getEnterpriseCode());
		Page<Map<String, Object>> page = viewRefundApplyDao.getNotRefundApplys(condition, processStatus);
		Page<ViewRefundApplyWrap> resultPage = new Page<>();
		resultPage.setPageNumber(page.getPageNumber());
		resultPage.setOffset(page.getOffset());
		resultPage.setPageSize(page.getPageSize());
		resultPage.setTotalItems(page.getTotalItems());
		resultPage.setTotalPages(page.getTotalPages());
		if (page == null || page.getItems() == null || page.getItems().isEmpty())
			return resultPage;
		List<Map<String, Object>> list = page.getItems();
		List<ViewRefundApplyWrap> wrapList = new ArrayList<>();
		String outSkuId = condition.getSkuId();
		String title = condition.getTitle();
		for (Map<String, Object> map : list) {
			String tid = (String) map.get("tid");
			String afterSaleType = (String) map.get("after_sale_type");
			List<ViewRefundApply> temp = viewRefundApplyDao.getNotViewRefundApplyByTid(tid, afterSaleType,outSkuId,title);
			ViewRefundApplyWrap wrap = new ViewRefundApplyWrap();
			wrap.setBuyerNick(temp.get(0).getBuyerNick());
			wrap.setRefundApplyList(temp);
			wrap.setShopName(temp.get(0).getShopName());
			wrap.setTid(tid);
			wrap.setTradesCreated(temp.get(0).getTradesCreated());
			wrap.setAfterSaleType(temp.get(0).getAfterSaleType());
			wrapList.add(wrap);
		}
		resultPage.setItems(wrapList);
		return resultPage;
	}

	@Override
	public Page<ViewRefundApplyWrap> getRefundedApplys(Condition condition) {
		// 成功
		String processStatus = RefundParams.PROCESS_STATUS_PROCESS;
		if (condition == null) {
			condition = new Condition();
		}
		condition.setEnterpriseCode(ContextHelper.getCurrentLoginInfo().getEnterprise().getEnterpriseCode());
		Page<Map<String, Object>> page = viewRefundApplyDao.getRefundApplys(condition, processStatus);
		Page<ViewRefundApplyWrap> resultPage = new Page<>();
		resultPage.setPageNumber(page.getPageNumber());
		resultPage.setOffset(page.getOffset());
		resultPage.setPageSize(page.getPageSize());
		resultPage.setTotalItems(page.getTotalItems());
		resultPage.setTotalPages(page.getTotalPages());
		if (page == null || page.getItems() == null || page.getItems().isEmpty())
		{
			return resultPage;
		}
		List<Map<String, Object>> list = page.getItems();
		List<ViewRefundApplyWrap> wrapList = new ArrayList<>();
		String outSkuId = condition.getSkuId();
		String title = condition.getTitle();
		for (Map<String, Object> map : list) {
			String tid = (String) map.get("tid");
			String afterSaleType = (String) map.get("after_sale_type");
			List<ViewRefundApply> temp = viewRefundApplyDao.getViewApplyBytid(tid, afterSaleType,outSkuId,title);
			ViewRefundApplyWrap wrap = new ViewRefundApplyWrap();
			wrap.setBuyerNick(temp.get(0).getBuyerNick());
			wrap.setRefundApplyList(temp);
			wrap.setShopName(temp.get(0).getShopName());
			wrap.setTid(tid);
			wrap.setTradesCreated(temp.get(0).getTradesCreated());
			wrap.setAfterSaleType(temp.get(0).getAfterSaleType());
			wrapList.add(wrap);
		}
		resultPage.setItems(wrapList);
		return resultPage;
	}

	@Override
	@Transactional
	public void doAgreeRemit(RefundApply refundApply) {
		Assert.notNull(refundApply, "操作对象");
		Assert.notNull(refundApply.getRefundId(), "操作对象");
		String refundId = refundApply.getRefundId();
		RefundApply temp = refundApplyDao.select(refundId);
		refundApply.setRefundResult(RefundParams.REFUND_RESULT_ACCEPT);
		refundApply.setProcessStatus(RefundParams.PROCESS_STATUS_SUCCESS);
		ReflectUtil.reflect(refundApply, temp);
		temp.setFeedbackTime(new Timestamp(System.currentTimeMillis()));
		temp.setStatus(RefundParams.ORDER_STATUS_SUCCESS);
		Boolean status = this.taobaoRefundAgree(temp);
		if (!status)
		{
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "调用天猫退款接口失败");
		}
		refundApplyDao.update(temp);
		// 生成订单处理日志
		orderLogDao.insert(tradesInfoService.createOrderLog(temp.getTid(), "1",
				ContextHelper.getCurrentLoginInfo().getAdminId(), "财务同意退款", BusiType.ORDER_REFUND.name(), "成功",
				refundApply.getCwRemark()));
	}

	private Boolean taobaoRefundAgree(RefundApply apply) {
		TradesInfo info = tradesInfoDao.select(apply.getTid());
		Map<String, String> shopMap = this.getShopMap(info.getShopId());
		TaobaoClient client = new DefaultTaobaoClient(shopMap.get(ShopConnAttr.SHOP_CONN_PROXURL),
				shopMap.get(ShopConnAttr.SHOP_CONN_APPKEY), shopMap.get(ShopConnAttr.SHOP_CONN_SECRET));
		RpRefundsAgreeRequest req = new RpRefundsAgreeRequest();
		// req.setCode("839212");//验证码
		if (apply.getMsgCode() != null)
		{
			req.setCode(apply.getMsgCode());
		}
		String infoStr = String.valueOf(apply.getRefundId()) + "|" + String.valueOf((int) (apply.getRefundFee() * 100))
				+ "|" + String.valueOf(apply.getRefundVersion()) + "|" + apply.getRefundPhase();
		req.setRefundInfos(infoStr);
		RpRefundsAgreeResponse rsp = null;
		try {
			String childAccountSessionKey = refundApplyDao.getChildAccountToken();
			rsp = client.execute(req, childAccountSessionKey);
			if (rsp.getMsgCode() != null) {
				if (rsp.getMsgCode().equals("10005") || rsp.getMsgCode().equals("10006")
						|| rsp.getMsgCode().equals("10000")) {
					throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "VALIDATE_MEESSAGE_NEED");
				}
			}
			if (rsp.getSubMsg() != null)
				throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + rsp.getErrorCode() + ","
						+ rsp.getMsg() + ";subCode:" + rsp.getSubCode() + "," + rsp.getSubMsg());
			if (rsp.getMsg() != null)
				throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "errorCode:" + rsp.getErrorCode() + ","
						+ rsp.getMsg() + ";subCode:" + rsp.getSubCode() + "," + rsp.getMsg());
			List<RefundMappingResult> results = rsp.getResults();
			if (results == null || results.isEmpty())
				return false;
			if (!results.get(0).getSucc())
				throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, results.get(0).getMessage());
			return results.get(0).getSucc();
		} catch (ApiException e) {
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "同步淘宝接口失败！A");
		}
	}

	@Override
	@Transactional
	public void doRefuseRemit(RefundApply refundApply) {
		Assert.notNull(refundApply, "操作对象");
		Assert.notNull(refundApply.getRefundId(), "操作对象");
		String refundId = refundApply.getRefundId();
		RefundApply temp = refundApplyDao.select(refundId);
		refundApply.setRefundResult(RefundParams.REFUND_RESULT_DENY);
		// refundApply.setProcessStatus(RefundParams.REFUND_RESULT_FAIL);
		ReflectUtil.reflect(refundApply, temp);
		temp.setStatus(RefundParams.ORDER_STATUS_SELLER_REFUSE_BUYER);
		refundApplyDao.update(temp);
		Boolean status = false;
		if (temp.getAfterSaleType().equals(RefundParams.AFTER_SALE_TYPE_REFUND_REFUND_GOODS)) {
			status = this.tmallRefuseRefundGoods(temp);
		} else {
			status = this.taobaoRefundRefuse(temp);
		}
		if (!status)
			throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "同步淘宝接口失败！");

		// 生成订单处理日志
		orderLogDao.insert(tradesInfoService.createOrderLog(refundApply.getTid(), "1",
				ContextHelper.getCurrentLoginInfo().getAdminId(), "财务拒绝退款", BusiType.ORDER_REFUND.name(), "成功",
				refundApply.getCwRefuseRemark()));
	}

	private Boolean taobaoRefundRefuse(RefundApply apply) {
		return this.tmallRefuseRefundApply(apply);
	}

	@Override
	public TradesInfo getChangeGoodsOrder(String tid) {
		Assert.notNull(tid, "交易单号");
		TradesInfo info = tradesInfoDao.getTradesInfo(tid);
		if (info == null)
			return null;
		List<TradesOrder> list = tradesOrderDao.getTradesOrderByTid(tid);
		/*if (list != null && !list.isEmpty()) {
			for (TradesOrder order : list) {
				List<RefundApply> temp = refundApplyDao.getListByTid(order.getTid(), order.getOuterSkuId());
				if (temp != null && !temp.isEmpty())
					order.setIsAfterSale(true);
				else
					order.setIsAfterSale(false);
			}
		}*/
		
		info.setTradesOrderList(list);
		return info;
	}

	@Override
	public TradesOrder getTradeOrder(String oid, Integer skuId,String orderId) {
		Assert.notNull(oid, "子交易单号");
		Assert.notNull(skuId, "商品编码");
		Assert.notNull(orderId, "交易明细ID");
		TradesOrder dto = new TradesOrder();
		dto.setOid(oid);
		TradesOrder order = tradesOrderDao.select(Integer.parseInt(orderId));
		if (order != null) {
			List<RefundApply> list = refundApplyDao.getListByTid(order.getTid(), String.valueOf(skuId));
			if (list != null && list.size() > 0)
			{
				throw ErrorUtils.wrap(ProductError.ENTERPRISE_NO_ROLE, "该订单已在退款或退货或换货中，不能重复申请售后服务！");
			}
			TradesInfo info = tradesInfoDao.select(order.getTid());
			Shop shop = shopDao.select(info.getShopId());
			order.setShop(shop);
		}
		return order;
	}

	@Override
	public Map<String, String> getShopMap(Integer shopId) {
		Shop shop = shopDao.select(shopId);
		String ruleInfo = shop.getRuleInfo();
		Map<String, String> shopMap = JsonUtil.parse(ruleInfo);
		shopMap.put("proxUrl", shop.getProxyURL());
		return shopMap;
	}

	@Override
	public void cwDoAgreeRefundGoods(RefundApply refundApply) {
		Assert.notNull(refundApply, "审核对象");
		Assert.notNull(refundApply.getRefundId(), "退货申请单号");
		Assert.notNull(refundApply.getCwRemark(), "财务退款说明");
		RefundApply apply = refundApplyDao.select(refundApply.getRefundId());
		apply.setOptRemark(apply.getOptRemark() == null ? refundApply.getCwRemark() : apply.getOptRemark());
		try {
			this.tmallAgreeRefundApply(apply);
		} catch (Exception e) {

		}
		this.doAgreeRemit(refundApply);
	}

	@Override
	public void updateRefundTradesInfo(String tid, String refundId,String optRemark) 
	{
		//校验发货接口入参是否规范
		Assert.notNull(tid, "订单号");
		Assert.notNull(refundId, "退货申请单号");
		Assert.notNull(optRemark, "备注");
		
		//查询售后单对应的销售订单并将其状态修改成 “打单发货”状态
		TradesInfo tradesInfo = tradesInfoDao.select(tid);
		//tradesInfo.setStatus("WAIT_SELLER_SEND_GOODS");
		tradesInfo.setOfflineStatus(OfflineStatus.WAIT_SEND_GOODS.name()); //可发货
		tradesInfo.setRemark(optRemark);
		tradesInfoDao.update(tradesInfo);
		
		//查询售后单并将其状态修改成 “拒绝退款(货)”状态  （此流程为内部流转不涉及第三方）
		RefundApply refundInfo = refundApplyDao.select(refundId);
		
		//处理状态
		refundInfo.setProcessStatus(RefundParams.PROCESS_STATUS_DENY);
		//退款状态
		refundInfo.setStatus(RefundParams.ORDER_STATUS_CLOSED);
		//refundInfo.setDescription(optRemark);
		refundInfo.setOptRemark(optRemark);
		refundApplyDao.update(refundInfo);
		
		/**
		 * 生成发货单数据
		 */
		List<ShoppDetail> shoppList =  shoppDetailDao.selectWhere(" tid = ?", tradesInfo.getTid());
		if(null == shoppList || shoppList.size() == 0)
		{
			Integer adminId = ContextHelper.getCurrentLoginInfo().getAdminId();
			Shopp shopp = createShopp(adminId, tradesInfo.getCompanyCode());
			
			//查询订单详情
			List<TradesOrder> tradesOrderList= tradesOrderDao.selectWhere(" tid = ?", tradesInfo.getTid());
			
			this.createShoppDetail(tradesOrderList, shopp.getShoppId());
		}
	}
	
	/**
	 * 新增发货单详情
	 * @param achieveOrders 订单详情列表
	 * @param shoppId 发货单号id
	 */
	public void createShoppDetail(List<TradesOrder> achieveOrders, Integer shoppId) {
		List<ShoppDetail> shoppDetails = new ArrayList<>();
		for (int i = 0; i < achieveOrders.size(); i++) {
			TradesOrder TradesOrder = achieveOrders.get(i);
			ShoppDetail detail = new ShoppDetail();
			detail.setTid(TradesOrder.getTid());
			detail.setShoppId(shoppId);
			detail.setOrderId(TradesOrder.getOrderId());
			detail.setNum(TradesOrder.getNum());
			shoppDetails.add(detail);
		}
		shoppDetailDao.insert(shoppDetails);
	}
	
	/**
	 * 新增发货单
	 * @param createUserId 创建人
	 * @param companyCode 快递公司编码
	 * @return
	 */
	public Shopp createShopp(Integer createUserId, String companyCode) {
		Shopp shopp = new Shopp();
		shopp.setCompanyCode(companyCode);
		shopp.setCreateTime(DateUtils.getCurrentTimestamp());
		shopp.setCreateUserId(createUserId);
		shopp.setShoppType(ShoppType.ORDER_SEND_GOODS.name());
		shopp.setStatus(ShoppStatus.WAIT_SEND_GOODS.name());
		shoppDao.insert(shopp);
		return shopp;
	}

}
